package com.iiapk.location;

import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.net.Uri;

public class CallerLocation {

	private static final String TAG = "CallerLocation";

	private static final Uri CALLERLOC_URI = Uri
			.parse("content://com.iiapk.location.CallerLocationProvider/CallerLoc");
	private static final Uri LOCINFO_URI = Uri
			.parse("content://com.iiapk.location.CallerLocationProvider/LocationInfo");
	private static final Uri CARRIERINFO_URI = Uri
			.parse("content://com.iiapk.location.CallerLocationProvider/CarrierInfo");
	private static final Uri IPPREFIX_URI = Uri
			.parse("content://com.iiapk.location.CallerLocationProvider/IPPrefix");

	private static final String mStrNationCode = "86";
	private static final String mStrNationCodePlus = "0086";
	private static final String mStrFetionCode = "12520";

	public static String getLocationInfo(final Context context, String number) {

		String location = null;
		String num = number.toString();
		if (null == context || null == num) {
			Log.e(TAG, "getLocation, params is null!");
			return null;
		}

		num = removePrefix(context, num);
		// whether the number is validate
		if (isValidNumber(context, num)) {
			/*
			 * Whether the number is start with "0" just like (010-******,
			 * 0151********)
			 */
			if (num.startsWith("0")) {
				num = num.substring(1);
				if (num.startsWith("10") || num.startsWith("2")) {
					/* its city code is "010" or "020"~"029" */
					String code = num.length() <= 2 ? num : num.substring(0, 2);
					Log.d(TAG,
							"getLocation, codes is " + Integer.parseInt(code));
					location = getCityByCode(context, Integer.parseInt(code));
				}
				// mobilePhone
				else if (num.startsWith("1") && num.length() >= 7) {
					/* It is a mobile phone number just like 013911111111 */
					location = getMobileLocationCarrier(context, num);
				}
				// fix phone
				else {
					Log.d(TAG, "getLocation, codes is " + num);
					/* It is a fix phone district number */
					String code = num.length() <= 3 ? num : num.substring(0, 3);
					location = getCityByCode(context, Integer.parseInt(code));
				}
			} else if (num.startsWith("1")) {
				if (num.length() >= 7) {
					location = getMobileLocationCarrier(context, num);
				} else {
					Log.e(TAG, "getLocation, number is invalid-1!");
					return null;
				}
			}
		} else {
			Log.e(TAG, "getLocation, number is invalid-1!");
			return null;
		}

		Log.d(TAG, "getLocation, location is " + location);
		return location;
	}

	private static String getMobileLocationCarrier(final Context context,
			String number) {
		Log.d(TAG, "getMobileLocationCarrier, number is " + number);
		String location = null;
		if (null == context || null == number || number.length() < 7) {
			Log.e(TAG, "getMobileLocationCarrier, number is invalid!");
			return null;
		}
		String numPre = number.substring(0, 7);
		long id = -1;
		Log.d(TAG, "getMobileLocationCarrier, numPre is " + numPre);
		id = (long) getLocationID(context, numPre);
		Log.d(TAG, "getMobileLocationCarrier, id is " + id);
		location = getCityByID(context, id);
		/* get the carrier info */
		String carPre = numPre.substring(0, 3);
		String carrier = getCarrier(context, carPre);
		Log.d(TAG, "getMobileLocationCarrier, carrier is " + carrier);
		if (null != carrier) {
			if (null != location) {
				location = location + " " + carrier;
			} else {
				location = carrier;
			}
		}
		Log.d(TAG, "getMobileLocationCarrier, locationcarrier is " + location);
		return location;
	}

	private static int getLocationID(final Context context, final String number) {
		int locationCodes = -1;
		if (null == context || null == number || number.length() == 0) {
			Log.e(TAG, "getLocationID, number is invalid!");
			return -1;
		}
		Log.d(TAG, "getLocationID, number is " + Integer.parseInt(number));
		try {
			Cursor cursor = context.getContentResolver().query(CALLERLOC_URI,
					new String[] { "location", "number" },
					"number=" + Integer.parseInt(number), null, null);
			if (null != cursor) {
				if (cursor.getCount() > 0) {
					cursor.moveToFirst();
					locationCodes = cursor.getInt(cursor
							.getColumnIndex("location"));
				}
				cursor.close();
			}
			Log.d(TAG, "getLocationCodes, codes is " + locationCodes);
		} catch (Exception e) {
			Log.e(TAG, "getLocationCodes, failed with " + e.toString());
		}
		return locationCodes;
	}

	private static String getCityByID(final Context context, final long id) {
		Log.d(TAG, "getCityByID, id is " + id);
		String city = null;
		if (null == context || id < 0) {
			Log.e(TAG, "getCityByID, params is invalid!");
			return null;
		}
		try {
			Cursor cursor = context.getContentResolver()
					.query(LOCINFO_URI, new String[] { "_id", "location" },
							"_id=" + id, null, null);
			if (null != cursor) {
				if (cursor.getCount() > 0) {
					cursor.moveToFirst();
					city = cursor.getString(cursor.getColumnIndex("location"));
				}
				cursor.close();
			}
			Log.d(TAG, "getCityByID, city is " + city);
		} catch (Exception e) {
			Log.e(TAG, "getCityByID, failed with " + e.toString());
		}
		return city;
	}

	private static String getCityByCode(final Context context, final int code) {
		Log.d(TAG, "getCityByCode, code is " + code);
		String city = null;
		if (null == context || code < 0) {
			Log.e(TAG, "getCityByCode, params is invalid!");
			return null;
		}
		try {
			Cursor cursor = context.getContentResolver().query(LOCINFO_URI,
					new String[] { "location", "code" }, "code=" + code, null,
					null);
			if (null != cursor) {
				if (cursor.getCount() > 0) {
					cursor.moveToFirst();
					city = cursor.getString(cursor.getColumnIndex("location"));
				}
				cursor.close();
			}
			Log.d(TAG, "getCityByCode, city is " + city);
		} catch (Exception e) {
			Log.e(TAG, "getCityByCode, failed with " + e.toString());
		}
		return city;
	}

	private static String getCarrier(final Context context, final String prefix) {
		Log.d(TAG, "getCarrier, prefix is " + prefix);
		String carrier = null;
		if (null == context || null == prefix || prefix.length() == 0) {
			Log.e(TAG, "getCarrier, params is invalid!");
			return null;
		}
		try {
			Cursor cursor = context.getContentResolver().query(CARRIERINFO_URI,
					new String[] { "Carrier" }, "prefix=" + prefix, null, null);
			if (null != cursor) {
				if (cursor.getCount() > 0) {
					cursor.moveToFirst();
					carrier = cursor
							.getString(cursor.getColumnIndex("Carrier"));
				}
				cursor.close();
			}
			Log.d(TAG, "getCarrier, carrier is " + carrier);
		} catch (Exception e) {
			Log.e(TAG, "getCarrier, failed with " + e.toString());
		}
		return carrier;
	}

	private static boolean isValidNumber(final Context context,
			final String number) {
		if (null == context || null == number || number.length() == 0) {
			Log.e(TAG, "isValidNumber, paras is invalid!");
			return false;
		}
		/*
		 * the length of number must be >= 5, because: a. if it's a mobile phone
		 * number, the length of location number is 5; b. if it's a telephone
		 * number, the length of city codes is 2 or 3("0" has been removed), and
		 * the normal number's length must be longer than 3
		 */
		if (number.length() < 3) {
			Log.e(TAG,
					"isValidNumber, number lenght is wrong-" + number.length());
			return false;
		}
		/* the number must be digits */
		for (int i = 0; i < number.length(); i++) {
			char digit = number.charAt(i);
			if ((digit > '9' || digit < '0') && digit != '+') {
				Log.e(TAG, "isValidNumber, has invalid char-" + digit);
				return false;
			}
		}
		return true;
	}

	public static String removePrefix(final Context context, String number) {
		if (number != null && number.length() > 0) {
			/* remove national codes "+86" and "0086" */
			number = removeNationCodePrefix(context, number);
			/* remove IP codes */
			number = removeIPPrefix(context, number);
			/* remove China Mobile Fetion codes */
			number = removeFetionPrefix(context, number);
		}

		return number;
	}

	private static boolean hasNationCode(final Context context,final String number) {
		if (null == context || null == number || number.length() == 0) {
			Log.e(TAG, "hasNationCode, paras is invalid!");
			return false;
		}
		if (number.startsWith(mStrNationCode)
				|| number.startsWith(mStrNationCodePlus)) {
			Log.d(TAG, "hasNationCode, it has nation code!");
			return true;
		} else {
			return false;
		}
	}

	private static String removeNationCodePrefix(final Context context,
			String number) {
		if (null == context || null == number || number.length() == 0) {
			Log.e(TAG, "removeNationCodePrefix, paras is invalid!");
			return number;
		}
		Log.d(TAG, "removeNationCodePrefix, begein, number is " + number);

		if (number.startsWith(mStrNationCode)) {
			number = number.substring(mStrNationCode.length());
		} else if (number.startsWith(mStrNationCodePlus)) {
			number = number.substring(mStrNationCodePlus.length());
		}
		Log.d(TAG, "removeNationCodePrefix, now number is " + number);
		return number;
	}

	private static String removeIPPrefix(final Context context, String number) {
		if (null == context || null == number || number.length() == 0) {
			Log.e(TAG, "removeIPPrefix, paras is invalid!");
			return number;
		}
		Log.d(TAG, "removeIPPrefix, begein, number is " + number);
		Cursor cursor = context.getContentResolver().query(IPPREFIX_URI,
				new String[] { "prefix" }, null, null, null);
		if (cursor == null) {
			Log.e(TAG, "removeIPPrefix, cursor is null!");
			return number;
		}
		cursor.moveToFirst();
		int count = cursor.getCount();
		if (count == 0) {
			Log.e(TAG, "removeIPPrefix, count is 0!");
			cursor.close();
			return number;
		}
		String ip = null;
		for (int i = 0; i < count; i++) {
			ip = cursor.getString(cursor.getColumnIndex("prefix"));
			Log.d(TAG, "removeIPPrefix, IP prefix is " + ip);
			if (ip != null && number.startsWith(ip)) {
				number = number.substring(ip.length());
				return number;
			}
			cursor.moveToNext();
		}
		cursor.close();
		Log.d(TAG, "removeIPPrefix, now number is " + number);
		return number;
	}

	private static String removeFetionPrefix(Context context, String number) {
		if (null == context || null == number || number.length() == 0) {
			Log.e(TAG, "removeFetionPrefix, paras is invalid!");
			return number;
		}
		Log.d(TAG, "removeFetionPrefix, begein, number is " + number);

		if (number.startsWith(mStrFetionCode)) {
			number = number.substring(mStrFetionCode.length());
		}
		Log.d(TAG, "removeFetionPrefix, now number is " + number);
		return number;
	}
}
